package vcp.client.GUI.mvc.view.custom;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Calendar;
import java.util.Date;

import javax.swing.JSpinner;
import javax.swing.SpinnerDateModel;

import org.joda.time.DateTime;

import vcp.client.interfaces.IMessage;

/**
 * <p>
 * custom J spinner date class
 * </p>
 * 
 * @author VCP team
 * 
 */
public class CustomJSpinnerDate extends JSpinner
{
	/**
	 * 
	 */
	private static final long serialVersionUID = - 1120569019774573015L;

	private final IMessage timeRetrieval;

	/**
	 * constructor
	 * 
	 * @param newModelDateTime
	 */
	public CustomJSpinnerDate ( DateTime newModelDateTime, IMessage timeRetrieval )
	{
		this.timeRetrieval = timeRetrieval;
		this.setUI(new CustomSpinnerUI(new IncrementActionHandler(), new DecrementActionHandler()));
		this.resetModel(newModelDateTime);
		this.spinnerInitialization();
	}

	/**
	 * reset model method
	 * 
	 * @param newModelDateTime
	 */
	public void resetModel ( DateTime newModelDateTime )
	{
		newModelDateTime = this.getRoundedTime(newModelDateTime, 1);
		this.setModel(new SpinnerDateModel(newModelDateTime.toDate(), null, null, Calendar.DAY_OF_YEAR));
	}

	/**
	 * spinner initialization method
	 */
	private void spinnerInitialization ()
	{
		this.getModel().setValue(this.initialRoundedDate());
		this.setEditor(new JSpinner.DateEditor(this, "dd/MM/yy HH:mm"));
		( (JSpinner.DateEditor) this.getEditor() ).getTextField().setEditable(false);
	}

	/**
	 * initializes to round date
	 * 
	 * @return rounded date
	 */
	private Date initialRoundedDate ()
	{
		DateTime currentTime = new DateTime();

		int roundedMinutes = ( ( currentTime.getMinuteOfHour() / 10 ) + 1 ) * 10;
		DateTime roundedTime = roundedMinutes == 60
													? currentTime.plusHours(1).withMinuteOfHour(0)
													: currentTime.withMinuteOfHour(roundedMinutes);

		return roundedTime.toDate();
	}

	/**
	 * 
	 * @param time
	 *            the time object to round minutes
	 * @param round
	 *            passing 1 will round up by tens, passing 0 will round down by
	 *            tens
	 * @return return <b>time</b> with rounded time
	 */
	private DateTime getRoundedTime ( DateTime time, int round )
	{
		int newTime = ( ( time.getMinuteOfHour() / 10 ) + round ) * 10;
		DateTime roundedTime = newTime == 60
											? time.plus(1).withMinuteOfHour(0)
											: time.withMinuteOfHour(newTime);

		return roundedTime;
	}

	/**
	 * <p>
	 * private class increment action handler
	 * </p>
	 * 
	 * @author VCP team
	 * 
	 */
	private class IncrementActionHandler implements ActionListener
	{
		@Override
		public void actionPerformed ( ActionEvent e )
		{
			DateTime modelDate = new DateTime(CustomJSpinnerDate.this.getModel().getValue());
			modelDate = modelDate.plusMinutes(10);
			CustomJSpinnerDate.this.getModel().setValue(modelDate.toDate());
		}
	}

	/**
	 * <p>
	 * private class decrement action handler
	 * </p>
	 * 
	 * @author VCP team
	 * 
	 */
	private class DecrementActionHandler implements ActionListener
	{
		@Override
		public void actionPerformed ( ActionEvent e )
		{
			DateTime modelDate = new DateTime(CustomJSpinnerDate.this.getModel().getValue());
			DateTime currentTime = CustomJSpinnerDate.this.timeRetrieval.requestCurrentClientDateTime();

			modelDate = CustomJSpinnerDate.this.getRoundedTime(modelDate, 0);
			currentTime = CustomJSpinnerDate.this.getRoundedTime(currentTime, 1);

			if ( this.isDecrementAllowed(currentTime, modelDate) )
			{
				modelDate = modelDate.minusMinutes(10);
				CustomJSpinnerDate.this.getModel().setValue(modelDate.toDate());
			}
		}

		/**
		 * 
		 * @param currentTime
		 *            current time to verify
		 * @param modelDate
		 *            current time to verify
		 * @return true if modelDate can be decremented according to currentTime
		 */
		private boolean isDecrementAllowed ( DateTime currentTime, DateTime modelDate )
		{
			boolean allowed = true;
			if ( ( currentTime.getHourOfDay() == modelDate.getHourOfDay() ) && ( currentTime.getMinuteOfHour() == modelDate.getMinuteOfHour() ) )
			{
				allowed = false;
			}
			else if ( ( currentTime.getHourOfDay() == modelDate.getHourOfDay() ) && ( currentTime.getMinuteOfHour() > modelDate.getMinuteOfHour() ) )
			{
				allowed = false;
			}
			return allowed;
		}

	}
}
